package main

import (
	_ "embed"
	"fmt"
	"github.com/aliee/init-box-golang/sshutil"
	"github.com/aliee/init-box-golang/util"
	"golang.org/x/crypto/ssh"
	"log"
	"os"
	"path/filepath"
)

const (
	tempDir   = "/tmp/nancal"
	filesPath = "/data/middlefiles-test-1"
)

var (
	oldIPs = []string{"192.168.31.141", "192.168.31.142", "192.168.31.143"}
)

func main() {
	// 1. 解析参数
	if len(os.Args) < 3 {
		log.Printf("Usage: %s [ip1] [ip2] [ip3] <password>\n", os.Args[0])
		os.Exit(1)
	}
	var ips []string
	var password string
	if len(os.Args) == 3 { // 单节点
		ips = []string{os.Args[1]}
		password = os.Args[2]
		log.Printf("The Ip address you entered is one node!")
	} else if len(os.Args) == 4 { // 双节点
		ips = []string{os.Args[1], os.Args[2]}
		password = os.Args[3]
		log.Printf("The Ip address you entered is two node!")
	} else if len(os.Args) == 5 { // 三节点
		ips = []string{os.Args[1], os.Args[2], os.Args[3]}
		password = os.Args[4]
		log.Printf("The Ip address you entered is three node!")
	} else {
		log.Printf("Usage: %s <ip1> [ip2] [ip3] <password>\n", os.Args[0])
		os.Exit(1)
	}

	// 2. 创建目录
	log.Printf("Create temp directory in the this node")
	if err := util.CreateDir(tempDir); err != nil {
		log.Printf("ERROR: %s, Exec command failed at the local node!", err.Error())
		return
	}

	log.Printf("Create a directory to save the configuration tar package!")
	if err := util.CreateDir(filesPath); err != nil {
		log.Printf("ERROR: %s, Exec command failed at the local node!", err.Error())
		return
	}

	log.Printf("Create the middlewares directory!")
	if err := util.RunLocal("mkdir -p /opt/nancal/base/{redis,nacos,rabbitmq,rocketmq,minio,nebula}"); err != nil {
		log.Printf("ERROR: %s, Exec command failed at the local node!", err.Error())
		return
	}

	log.Printf("create redis-sentinel directory! ")
	if err := util.CreateDir("/opt/nancal/base/redis/sentinel"); err != nil {
		log.Printf("ERROR: %s, Exec command failed at the local node!", err.Error())
		return
	}

	log.Printf("create redis-logs directory")
	if err := util.CreateDir("/opt/nancal/base/redis/logs"); err != nil {
		log.Printf("ERROR: %s, Exec command failed at the local node!", err.Error())
		return
	}

	// 3. 建立 SSH 连接
	conns := make([]*ssh.Client, len(ips))
	for i, ip := range ips {
		client, _, err := sshutil.NewSession(ip, 22, "root", password)
		if err != nil {
			log.Fatalf("connect %s failed: %v", ip, err)
		}
		conns[i] = client
		defer client.Close()
	}

	// 4. 远端创建目录
	for _, c := range conns {
		if err := sshutil.RunRemote(c, "mkdir -p /opt/nancal/base/{redis,nacos,rabbitmq,rocketmq,minio,nebula}"); err != nil {
			log.Printf("exec remote command 'create dir: /opt/nancal/base/{redis,nacos,rabbitmq,rocketmq,minio,nebula}'  error: %s", err.Error())
		}
		if err := sshutil.RunRemote(c, "mkdir -p /opt/nancal/base/redis/{sentinel,logs,etc}"); err != nil {
			log.Printf("exec remote command 'create dir: /opt/nancal/base/redis/{sentinel,logs,etc}' error: %s", err.Error())
		}
	}

	// 5. 生成 conf.tgz 并解压
	confFile := filepath.Join(tempDir, "conf.tgz")
	if err := os.WriteFile(confFile, confTgz, 0o644); err != nil {
		log.Fatalf("write conf.tgz failed: %v", err)
	}
	if err := util.ExtractTarGz(confFile, filesPath); err != nil {
		log.Fatalf("extract conf.tgz failed: %v", err)
	}

	// 6. 替换 IP
	for _, node := range []string{"node1", "node2", "node3"}[:len(ips)] {
		for idx, old := range oldIPs[:len(ips)] {
			cmd := fmt.Sprintf(`sed -i 's/%s/%s/g' %s/%s/*`,
				old, ips[idx], filesPath, node)
			if err := util.RunLocal(cmd); err != nil {
				log.Printf("Exec command failed at the local node!")
				return
			}
		}
	}

	// 7. 逐个文件上传
	commonFiles := []string{
		"sentinel.conf", "redis.conf", "cluster.conf", "miniod", "miniod.service",
		"nebula-graphd.conf", "nebula-metad.conf", "nebula-storaged.conf",
	}
	brokerFiles := []string{"broker-n0.conf", "broker-n1.conf", "broker-n2.conf"}
	confDirs := []string{
		"/opt/nancal/base/redis", "/opt/nancal/base/redis", "/opt/nancal/base/nacos",
		"/opt/nancal/base/minio", "/opt/nancal/base/minio", "/opt/nancal/base/nebula", "/opt/nancal/base/nebula",
		"/opt/nancal/base/nebula",
	}

	for nodeIdx, node := range []string{"node1", "node2", "node3"}[:len(ips)] {
		// 公共配置
		for i, f := range commonFiles {
			local := filepath.Join(filesPath, node, f)
			remote := filepath.Join(confDirs[i], f)
			for _, c := range conns {
				if err := sshutil.UploadFile(c, local, remote); err != nil {
					log.Printf("upload %s -> %s failed: %v", local, remote, err)
				}
			}
		}
		// broker 单独处理
		local := filepath.Join(filesPath, node, brokerFiles[nodeIdx])
		remote := filepath.Join("/opt/nancal/base/rocketmq", brokerFiles[nodeIdx])
		for _, c := range conns {
			if err := sshutil.UploadFile(c, local, remote); err != nil {
				log.Printf("upload %s -> %s failed: %v", local, remote, err)
			}
			if err := sshutil.RunRemote(c, "cp /opt/nancal/base/minio/miniod /etc/sysconfig/miniod && cp /opt/nancal/base/minio/miniod.service /etc/systemd/system/miniod.service "); err != nil {
				log.Printf("exec remote command 'minio' error: %s", err.Error())
			}
			if err := sshutil.RunRemote(c, "cp /opt/nancal/base/redis/sentinel.conf /opt/nancal/base/redis/etc/ && cp /opt/nancal/base/redis/redis.conf /opt/nancal/base/redis/etc/"); err != nil {
				log.Printf("exec remote command 'redis' error: %s", err.Error())
			}
		}
		log.Printf("the %s configuration complete!", node)
	}

	// 8. 打印本机 IP
	if ip, err := util.LocalIPv4(); err == nil {
		log.Printf("本机 IP: %s\n", ip)
	}

}

//go:embed conf.tgz
var confTgz []byte
